﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using UserControl = System.Windows.Controls.UserControl;

namespace MetroHome
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool[,] _cellsMatrix;
        private WidgetManager _widgetManager;
        private const int MaxItemSize = 135;


        private double x;
        private double y;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void WindowSourceInitialized(object sender, EventArgs e)
        {
            Left = SystemInformation.WorkingArea.Left;
            Top = SystemInformation.WorkingArea.Top;
            Width = SystemInformation.WorkingArea.Width;
            Height = SystemInformation.WorkingArea.Height;

            MarkupGrid();

            _widgetManager = new WidgetManager();
            _widgetManager.FindWidgets();
            foreach (var widget in _widgetManager.Widgets)
            {
                if (App.Sett.LoadedWidgets != null && App.Sett.LoadedWidgets.Contains(widget.WidgetName))
                {
                    widget.Load();

                    int col = Grid.GetColumn(widget);
                    int row = Grid.GetRow(widget);
                    if (col != 0 || row != 0)
                    {
                        int colspan = Grid.GetColumnSpan((UIElement)sender);
                        int rowspan = Grid.GetRowSpan((UIElement)sender);

                        ReserveSpace(col, row, colspan, rowspan);
                    }
                    else
                        PlaceWidget(widget);
                    RootGrid.Children.Add(widget);

                    widget.MouseLeftButtonDown += WidgetMouseLeftButtonDown;
                    widget.MouseLeftButtonUp += WidgetMouseLeftButtonUp;
                    widget.MouseMove += WidgetMouseMove;
                }
            }
        }

        void WidgetMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (Mouse.Captured == null && e.LeftButton == MouseButtonState.Pressed)
            {
                Mouse.Capture((IInputElement)sender);
                RootGrid.Children.Remove((UIElement)sender);
                DragCanvas.Children.Add((UIElement)sender);

                Canvas.SetLeft((UIElement)sender, e.GetPosition(DragCanvas).X - x);
                Canvas.SetTop((UIElement)sender, e.GetPosition(DragCanvas).Y - y);

                int col = Grid.GetColumn((UIElement)sender);
                int row = Grid.GetRow((UIElement)sender);
                int colspan = Grid.GetColumnSpan((UIElement)sender);
                int rowspan = Grid.GetRowSpan((UIElement)sender);

                //ShowReservedCells();
                FreeSpace(col, row, colspan, rowspan);
                RootGrid.ShowGridLines = true;
                ((FrameworkElement)sender).Width = ((FrameworkElement)sender).ActualWidth;
                ((FrameworkElement)sender).Height = ((FrameworkElement)sender).ActualHeight;
            }
            if (Mouse.Captured == sender)
            {
                Canvas.SetLeft((UIElement)sender, e.GetPosition(DragCanvas).X - x);
                Canvas.SetTop((UIElement)sender, e.GetPosition(DragCanvas).Y - y);
            }
        }

        void WidgetMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            x = e.GetPosition((IInputElement)sender).X;
            y = e.GetPosition((IInputElement)sender).Y;
            /*
            Mouse.Capture((IInputElement)sender);
            RootGrid.Children.Remove((UIElement)sender);
            DragCanvas.Children.Add((UIElement)sender);

            Canvas.SetLeft((UIElement)sender, e.GetPosition(DragCanvas).X - x);
            Canvas.SetTop((UIElement)sender, e.GetPosition(DragCanvas).Y - y);

            int col = Grid.GetColumn((UIElement)sender);
            int row = Grid.GetRow((UIElement)sender);
            int colspan = Grid.GetColumnSpan((UIElement)sender);
            int rowspan = Grid.GetRowSpan((UIElement)sender);

            //ShowReservedCells();
            FreeSpace(col, row, colspan, rowspan);
            RootGrid.ShowGridLines = true;
            ((FrameworkElement)sender).Width = ((FrameworkElement)sender).ActualWidth;
            ((FrameworkElement)sender).Height = ((FrameworkElement)sender).ActualHeight;*/
        }

        void WidgetMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (Mouse.Captured == sender)
            {
                Mouse.Capture(null);
                DragCanvas.Children.Remove((UIElement) sender);
                RootGrid.Children.Add((UIElement) sender);

                var coords = new Point(Math.Truncate(e.GetPosition(DragCanvas).X/MaxItemSize),
                                       Math.Truncate(e.GetPosition(DragCanvas).Y/MaxItemSize));
                int gridWidth = _cellsMatrix.GetLength(0);
                int gridHeight = _cellsMatrix.GetLength(1);

                if ((int) coords.X < gridWidth && (int) coords.Y < gridHeight &&
                    _cellsMatrix[(int) coords.X, (int) coords.Y])
                    PlaceWidget((UserControl) sender);
                else
                {

                    Grid.SetColumn((UIElement) sender, (int) coords.X);
                    Grid.SetRow((UIElement) sender, (int) coords.Y);

                    int colspan = Grid.GetColumnSpan((UIElement) sender);
                    int rowspan = Grid.GetRowSpan((UIElement) sender);

                    ReserveSpace((int) coords.X, (int) coords.Y, colspan, rowspan);
                }
                //HideReservedCells();
                RootGrid.ShowGridLines = false;
                ((FrameworkElement) sender).Width = double.NaN;
                ((FrameworkElement) sender).Height = double.NaN;
            }
            else
            {
                HubGrid.Children.Clear();
                RootGrid.Visibility = Visibility.Collapsed;
                HubGrid.Children.Add(((Widget)sender).GetHub());
            }
        }

        private void MarkupGrid()
        {
            RootGrid.RowDefinitions.Clear();
            RootGrid.ColumnDefinitions.Clear();
            int rows = (int)(this.Height - RootGrid.Margin.Top - RootGrid.Margin.Bottom) / MaxItemSize;
            int columns = (int)(this.Width - RootGrid.Margin.Left - RootGrid.Margin.Right) / MaxItemSize;

            _cellsMatrix = new bool[columns, rows];

            for (var i = 0; i < rows; i++)
            {
                var row = new RowDefinition();
                RootGrid.RowDefinitions.Add(row);
            }

            for (var i = 0; i < columns; i++)
            {
                var column = new ColumnDefinition();
                RootGrid.ColumnDefinitions.Add(column);
            }
        }

        //find cells for widget
        public void PlaceWidget(UserControl widget)
        {
            int rowSpan = Grid.GetRowSpan(widget);
            int colSpan = Grid.GetColumnSpan(widget);

            int gridHeight = _cellsMatrix.GetLength(1);
            for (var col = 0; col < gridHeight; col++)
            {
                //if we found a column with enough vertical space, check for horizontal space
                var freeCol = GetFreeColumn(col, rowSpan);
                if (freeCol > -1)
                {
                    int rowLength = freeCol + rowSpan;
                    for (var row = freeCol; row < rowLength; row++)
                    {
                        var freeRow = GetFreeRow(row, col, colSpan);
                        if (freeRow > -1)
                        {
                            Grid.SetColumn(widget, col);
                            Grid.SetRow(widget, row);

                            //reserve space in matrix
                            ReserveSpace(col, row, colSpan, rowSpan);
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Check if column has enough space for tile
        /// </summary>
        /// <param name="c">Column index</param>
        /// <param name="length">Rowspan</param>
        /// <returns>Number of row where tile can be placed. If there are no such rows, returns -1</returns>
        private int GetFreeColumn(int c, int length)
        {
            int begin = -1;
            int end = 0;
            for (int i = 0; i < _cellsMatrix.GetLength(0); i++)
            {
                if (_cellsMatrix[c, i] == false)
                {
                    if (begin == -1)
                    {
                        begin = i;
                        end = i;
                    }
                    else
                        end = i;
                }
                else
                {
                    begin = -1;
                    end = 0;
                }

                if (end - begin + 1 == length)
                    return begin;
            }

            return -1;
        }

        private int GetFreeRow(int r, int index, int length)
        {
            int begin = -1;
            int end = -1;
            for (int i = index; i < index + length /*&& i < cellsMatrix.GetLength(1)*/; i++)
            {
                if (_cellsMatrix[i, r] == false)
                {
                    if (begin == -1)
                    {
                        begin = i;
                        end = i;
                    }
                    else
                        end = i;
                }
                else
                {
                    begin = -1;
                    end = -1;
                }

                if (end - begin + 1 == length)
                    return begin;
            }

            return -1;
        }

        private void ReserveSpace(int col, int row, int colspan, int rowspan)
        {
            int gridWidth = _cellsMatrix.GetLength(0);
            int gridHeight = _cellsMatrix.GetLength(1);

            if (col + colspan < gridWidth && row + rowspan < gridHeight)
            {
                for (int i = col; i < col + colspan; i++)
                    _cellsMatrix[i, row] = true;
                for (int j = row; j < row + rowspan; j++)
                    _cellsMatrix[col, j] = true;
            }
        }

        private void FreeSpace(int col, int row, int colspan, int rowspan)
        {
            int gridWidth = _cellsMatrix.GetLength(0);
            int gridHeight = _cellsMatrix.GetLength(1);

            if (col + colspan < gridWidth && row + rowspan < gridHeight)
            {
                for (int i = col; i < col + colspan; i++)
                    _cellsMatrix[i, row] = false;
                for (int j = row; j < row + rowspan; j++)
                    _cellsMatrix[col, j] = false;
            }
        }

        private void ShowReservedCells()
        {
            int gridHeight = _cellsMatrix.GetLength(0);
            int gridWidth = _cellsMatrix.GetLength(1);

            for (int i = 0; i < gridHeight; i++)
                for (int j = 0; j < gridWidth; j++)
                {
                    var r = new TextBlock() { Background = Brushes.Red };
                    if (_cellsMatrix[i, j])
                    {
                        Grid.SetRow(r, j);
                        Grid.SetColumn(r, i);
                        RootGrid.Children.Add(r);
                        r.Text = RootGrid.Children.IndexOf(r).ToString();
                    }
                }
        }

        private void HideReservedCells()
        {
            int index = 0;
            while (RootGrid.Children.OfType<TextBlock>().Count() > 0)
            {
                if (RootGrid.Children[index] is TextBlock)
                {
                    RootGrid.Children.RemoveAt(index);
                    index = 0;
                    continue;
                }
                index++;
            }
        }

        private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (HubGrid.Children.Count > 0)
            {
                HubGrid.Children.Clear();
                RootGrid.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {

                if (WidgetsLibrary.ActualWidth > 0)
                {
                    Storyboard s = Resources["ArrowAnimRight"] as Storyboard;
                    s.Completed += new EventHandler(MoveRightAnimCompleted);
                    s.Begin();

                    foreach (LibraryItem item in WidgetsLibrary.Children)
                    {
                        item.MouseLeftButtonUp -= item_MouseLeftButtonUp;
                        item.IconImage = null;
                    }
                    //WidgetsLibrary.Children.Clear();
                }
                else
                {
                    Storyboard s = Resources["ArrowAnimLeft"] as Storyboard;
                    s.Begin();

                    foreach (Widget w in _widgetManager.Widgets)
                    {
                        LibraryItem item = new LibraryItem();
                        item.Title = w.WidgetName;
                        item.Icon = new BitmapImage(new Uri(w.WidgetIcon));
                        item.Order = WidgetsLibrary.Children.Count;
                        item.MouseLeftButtonUp += item_MouseLeftButtonUp;
                        WidgetsLibrary.Children.Add(item);
                    }
                }
            }
        }

        void MoveRightAnimCompleted(object sender, EventArgs e)
        {
            WidgetsLibrary.Children.Clear();
        }

        void item_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            foreach (var widget in _widgetManager.Widgets)
            {
                if (widget.WidgetName == ((LibraryItem)sender).Title)
                {
                    if (widget.IsWidgetLoaded)
                    {
                        widget.Unload();


                        widget.MouseLeftButtonDown -= WidgetMouseLeftButtonDown;
                        widget.MouseLeftButtonUp -= WidgetMouseLeftButtonUp;
                        widget.MouseMove -= WidgetMouseMove;

                        int col = Grid.GetColumn(widget);
                        int row = Grid.GetRow(widget);

                        int colspan = Grid.GetColumnSpan(widget);
                        int rowspan = Grid.GetRowSpan(widget);
                        FreeSpace(col, row, colspan, rowspan);

                        RootGrid.Children.Remove(widget);
                    }
                    else
                    {
                        widget.Load();
                        PlaceWidget(widget);
                        RootGrid.Children.Add(widget);

                        widget.MouseLeftButtonDown += WidgetMouseLeftButtonDown;
                        widget.MouseLeftButtonUp += WidgetMouseLeftButtonUp;
                        widget.MouseMove += WidgetMouseMove;

                        Image_MouseLeftButtonDown(sender, e);
                    }
                }
            }
        }

        private void MenuItemClick(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void this_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            App.Sett.LoadedWidgets = new List<string>();

            foreach (Widget w in _widgetManager.Widgets)
            {
                if (w.IsWidgetLoaded)
                {
                    App.Sett.LoadedWidgets.Add(w.WidgetName);
                    w.Unload();
                }
            }

            try
            {
                App.Sett.Write(App.Path + "\\Config\\Home.conf");
            }
            catch (Exception)
            {

            }
        }
    }
}
